from guiCommon import LeVinCompactButton, CompactTextInput, LeVinIconLabel, LeVinButton, LeVinSpinBox, LeVinCombo, LeVinPopup, LeVinIconCombo
import guiCommon
import world.wineObjects as wineObjects

import wineSelector
import levinCommon
from world.bottle import Bottle

from kivy.properties import ListProperty, ObjectProperty
from kivy.uix.boxlayout import BoxLayout

from kivyext.combobox import ComboBoxBase, ComboBox

from kivyext.treegridview import MyListView
from kivy.uix.screenmanager import Screen


class SelectorBase(object):
    onlyGui = False # When used in a custom selection window, this is True : the instance will not act as selector, and only copy its information to the actual selector.

    def __call__(self,o):
        t = self.test(o)
        if not t:
            o.is_visible =False
        return t

    def defaultChoice(self):
        pass

    def setupInternalWid(self):
        pass
    
class ColorSelectorWid( SelectorBase, wineSelector.ColorSelector, LeVinIconCombo):
    """This represent a fast filter widget in the main screen to select wine color"""
    default_icon = levinCommon.iconPath('compressGlass.png')
    mainInstance = None
    def __init__(self, **kargs):
        kargs['entryWidClass'] = LeVinCompactButton
        super(ColorSelectorWid, self).__init__(editable=False,
                                               text ='',
                                               content = [ _("All colors")]+wineObjects.colors, **kargs)
        self.icon_src = self.default_icon 
        self.icons = [self.default_icon,]+[ levinCommon.iconPath('compressGlass'+l+'.png') for l in ['R','W','P','S'] ]
        self.padding_y = 2
        self.padding_x = 2
        self.selected_index = 0
        self.on_choice_validated(0)
        

    def on_choice_validated(self, *l):
        i= self.selected_index
        if not self.onlyGui: # can be false if copying state between 2 instances
            if i == 0:
                levinCommon.wineWorld.removeSelector(self)
            else:
                self.wcolor =i-1
                levinCommon.wineWorld.addSelector(self)
        self.icon_src = self.icons[i] 
        self.text=''

    def reset(self):
        self.select_first()

    def defaultChoice(self):
        self.on_choice_validated(0)        
        self.text = ''

    def copyFrom(self, other):
        self.select_index(other.selected_index)
        self.on_choice_validated()

    def setupInternalWid(self):
        self.buildDropDown()

    def updateMainInstance(self):
        if self is not self.mainInstance:
            self.mainInstance.select_index(self.selected_index)
            


class NumSelectorWid(SelectorBase, wineSelector.NumInCellarSelector, LeVinIconCombo):
    """This represent a fast filter widget in the main screen to select on number of remaining bottles
     (No more on main screen ?) """

    default_icon = levinCommon.iconPath('incellar_icon.png')    
    mainInstance = None

    defaultSelection = 'cellar'
    
    def __init__(self, **kargs):
        kargs['entryWidClass'] = LeVinCompactButton        
        super(NumSelectorWid, self).__init__(editable=False, text='',
                                             content = [ _("In cellar"),_("All"), _("No more"), ], **kargs)
        self.icons = [levinCommon.iconPath(s) for s in ['incellar_icon.png','allbottles_icon.png','nomore_icon.png'] ]
        self.icon_src = self.default_icon 
        self.switch(self.defaultSelection)
        self.text=''
        self.selected_index = 0


        levinCommon.wineWorld.addSelector(self)

    def updateMainInstance(self):
        if self is not self.mainInstance:
            self.mainInstance.select_index(self.selected_index)
        
    def on_choice_validated(self,  *l):
        i= self.selected_index

        if not self.onlyGui: # can be false if copying state between 2 instances 
            levinCommon.wineWorld.removeSelector(self)

            if i == 0:
                self.switch('incellar')
            elif i==1:
                self.switch('incellarornomore')
            else:
                self.switch('nomore')
            levinCommon.wineWorld.addSelector(self)
            levinCommon.wineWorld.updateSelector()

        self.text=''
        self.icon_src = self.icons[i] 


    def defaultChoice(self):
        self.on_choice_validated(0)        
        self.text = ''

    def reset(self):
        self.switch( self.defaultSelection)

    def copyFrom(self, other):
        self.select_index(other.selected_index)
        self.on_choice_validated()
        
    def setupInternalWid(self):
        self.buildDropDown()



class TextSelectorWid(SelectorBase, wineSelector.TextSelector, CompactTextInput):
    """This represent a fast filter widget in the main screen to select wine on wine name"""
    mainInstance = None
    def __init__(self, **kargs):
        super(TextSelectorWid, self).__init__( **kargs)
        Bottle.compactStringBuilder = Bottle.compactStringBuilder_cru_app

    def on_text(self, *l):
        if not self.onlyGui:
            if l[1] != "":
                levinCommon.wineWorld.addSelector(self)
            else:
                levinCommon.wineWorld.removeSelector(self)

    def updateMainInstance(self):
        if self is not self.mainInstance:
            self.mainInstance.text = self.text

    def reset(self):
        self.text= ''

    def copyFrom(self, other):
        self.text = other.text


##*******************************************************************
##*******************************************************************

class CustomSelectorStarter( LeVinButton ):
    """This is the button to call the advanced filter screen.
    startCustom() is called from on_press in kv."""

    def startCustom(self, *l):
        topW = guiCommon.appComponents.topWindow
        customW = CustomSelectorWidget.instance
        ## for sc in topW.screens :
        ##     print sc, sc.name, sc.pos, sc.size
        
        if not customW.parent_popup:
            customW.parent_popup = True
            for fastSel in customW.fastSelector:
                fastSel.setupInternalWid() # !! important
        guiCommon.appComponents.topWindow.current = 'advancedSelectors'
        


##*******************************************************************
##*******************************************************************

class CustomSelectorWidget( Screen):
    """Main widget for custom selector creation """
    instance = None
    parent_popup = None
    currenSelector = []
    selectorWids = ListProperty([])
    fastSelector = ListProperty([])
    
    def __init__(self, **args):
        super(CustomSelectorWidget,self).__init__(**args)
        #self.reset()

    def validate(self, *l):
        """Actions taken after 'Ok' has been clicked in the advanced selectors screen"""

        # Block any selection while the list of selector is updated
        levinCommon.wineWorld.blockUpdateSelector(True) 
        levinCommon.wineWorld.activeSelectors = []
        for selW in self.selectorWids:
            if selW.selModifier:
                sel = selW.selModifier.buildSelector()
                levinCommon.wineWorld.addSelector(sel)
                selW.saveState()

        for sel in self.fastSelector:
            sel.updateMainInstance()

        levinCommon.wineWorld.blockUpdateSelector(False)            
        levinCommon.wineWorld.updateSelector()

        if self.parent_popup:
            guiCommon.appComponents.topWindow.current = 'mainScreen'
        
    def reset(self, *l):
        for s in self.selectorWids:
            s.clear()

        for s in self.fastSelector:
            s.reset()

    def cancel(self, *l):
        if self.parent_popup :
            for s in self.selectorWids:
                s.restoreState()
            for s in self.fastSelector:
                s.reset()
            guiCommon.appComponents.topWindow.current = 'mainScreen'

    


##*******************************************************************
##*******************************************************************
class CreateSelector( BoxLayout ):
    """Widget for creation of a single filter"""
    
    criteria = ObjectProperty(None) # a  FilteredCriteriaCombo (see .kv). Choose on what wine criteria to filter. When set, a new modifier is created
    selModifier = ObjectProperty(None, allownone=True) # a SelectorModifier. Builds the actual filter.

    #state = None #(0,None)
    state = (-1,None)


    _restoring_state = False
    
    def clear(self, *l):
        self.criteria.clear()
        self.clearWidgets()
        self.selModifier = None
        self.currentCriteriaIndex = -1

    def clearWidgets(self):
        if self.selModifier:
            for w in self.selModifier.widgets:
                self.remove_widget(w)
        
        
    def criteriaSelected(self, *l):
        if self._restoring_state:
            return
        index = self.criteria.selected_index
        if index==0:
            self.clear()
            return

        key = selectorTypes[index-1][0]

        if self.currentCriteriaIndex != index:
            self.clearWidgets()
        for (k,v) in selectorTypes:
            if k == key :
                #self.criteria.text = k
                self.buildCreator(k, v)
                self.currentCriteriaIndex = index
                return

    def buildCreator(self, criteria,  modifierCreator):
        self.selModifier = modifierCreator()
        self.selModifier.parent = self
        for w in self.selModifier.widgets:
            self.add_widget(w)

        
    def saveState(self):
        self.selModifier.saveState()
        self.state = (self.criteria.selected_index, self.selModifier)


    def restoreState(self):
        if self.state[1] is None:
            self.clear()
            return
        self.selModifier = self.state[1]
        self.selModifier.restoreState()
        self._restoring_state = True
        self.criteria.select_index(self.state[0]) # this modifies selModifier !!
        for w in self.selModifier.widgets:
            if w not in self.children:
                self.add_widget(w)

        self._restoring_state = False

class FilteredCriteriaCombo( LeVinIconCombo):
    def_content = []
    icons = []
    default_icon = ''
    parent = None
    def __init__(self, **args):
        super(FilteredCriteriaCombo,self).__init__(**args)
        self.change_content( self.def_content)
        self.text = _('No filter')
    def clear(self, *l):
        self.init()

    def init(self):
        #self.select_index(0)
        self.text = _('No filter')

            


class ClearSelectorButton(LeVinButton):
    pass
class SelectorModifier(object):
    """Base class for to handle a Selector object and the related widget.
    This class provides a buildSelector() function which returns the selector object.
    buildSelector() dynamically create the selection code from a bottle attribute (for example) so the class is kept very generic,
    and at the same time the att or selection interpretation/lookups is done only once.
    """
    widgets = []
    state = None
    clearButton = None
    parent = None
    def __init__(self, att, **args):
        self.att = att        
        for k,v in args.iteritems():
            setattr(self,k,v)

    def buildSelector(self):
        testF = self.buildSelectionCode(self.att)
        testFcode = compile(testF,'','exec')
        d = {}
        exec testFcode in {},d
        testFc = d['test']
        # testFc  = compile testF
        selClass = type("Selector"+self.att, (SelectorBase,), {})
        selClass.test = testFc
        selClass.testCode = testF
        return selClass()

    @classmethod
    def factory(cls, att, **args):
        def _f():
            o = cls(att=att, **args)
            o.setupWidgets()
            return o
        return _f

    def _setupWidgets(self, *wids):
        if self.clearButton is None:
            self.clearButton = ClearSelectorButton(size_hint = (0.1,None))
            self.clearButton.parent = self.parent
        self.widgets = list(wids)+[ self.clearButton ] 
        return self.widgets

class NumericalSelectorModifier(SelectorModifier):
    testStr = """def test(self, b):
        return b.%s %s %f"""

    def setupWidgets(self):
        self.relationWid = LeVinCombo( content = [ '>', '=', '<'], size_hint = (0.3,None) )
        self.valueWid = LeVinSpinBox( value=self.defaultv, size_hint = (0.3,None))
        return self._setupWidgets( self.relationWid, self.valueWid  )
    
    def buildSelectionCode(self, att):
        value = self.valueWid.value
        rel = self.relationWid.text
        if rel == '=': rel = '=='        
        return self.testStr%(att, rel, value)

    def saveState(self):
        self.state =[ self.relationWid.selected_index , self.valueWid.value]

    def restoreState(self):
        self.relationWid.select_index( self.state[0])
        self.valueWid.value = self.state[1]

class TextSelectorModifier(SelectorModifier):
    defaultv = ''
    testStr = """def test(self, b):
        return b.%s and '%s' in b.%s"""

    def setupWidgets(self):
        self.relationWid = LeVinCombo( content = [ _('contains') ] , size_hint = (0.3,None), text=_('contains'))
        self.valueWid = CompactTextInput( text=self.defaultv , multiline=False, size_hint = (0.3,None))
        return self._setupWidgets( self.relationWid, self.valueWid  )

    def buildSelectionCode(self, att):
        return self.testStr%(att,self.valueWid.text, att)

    def saveState(self):
        self.state =[ self.relationWid.selected_index , self.valueWid.text]
    def restoreState(self):
        self.relationWid.select_index( self.state[0])
        self.valueWid.text = self.state[1]

class TastingTextSelectorModifier(TextSelectorModifier):
    testStr = """def test(self, b):
        if b.tastings is None:return False
        return any('%s' in t.%s for t in b.tastings if t.%s)"""

    def buildSelectionCode(self, att):
        return self.testStr%(self.valueWid.text, att, att)


def initialize():
    # build a default instance
    #wid = CustomSelectorWidget()
    wid = CustomSelectorWidget(name='advancedSelectors')
    guiCommon.appComponents.topWindow.add_widget(wid)
    mainScreen = guiCommon.appComponents.mainScreen

    CustomSelectorWidget.instance = wid

    ColorSelectorWid.mainInstance = mainScreen.quickColorSelector
    TextSelectorWid.mainInstance  = mainScreen.quickTextSelector
    NumSelectorWid.mainInstance   = wid.fastSelector[1] # see .kv file !
    
    for fastSel in wid.fastSelector:
        fastSel.onlyGui = True
    NumSelectorWid.mainInstance.onlyGui = False


    FilteredCriteriaCombo.default_icon = ''
    FilteredCriteriaCombo.icons = [ '' ]+[ '' for v in selectorTypes ]
    wid.reset()


    for wc in [ColorSelectorWid, NumSelectorWid, TextSelectorWid]:
        wc.mainInstance.defaultChoice()
    wid.validate()
                
from datetime import date

# format is
# (wine_attribute, SelectorModifier instance)
selectorTypes = [
    ("numInStock", NumericalSelectorModifier.factory('numInStock', defaultv=0)),
    ("productor", TextSelectorModifier.factory('productor')),
    ("millesime", NumericalSelectorModifier.factory("millesime",defaultv=date.today().year)),
    ("comment",   TastingTextSelectorModifier.factory('comment')),
    ("numTastings", NumericalSelectorModifier.factory('numTastings()', defaultv=0)),
    
    ]

from world.wineObjects import WineObjectTranslation as wot
FilteredCriteriaCombo.def_content = [ _('No filter') ]+[ wot[a] for (a,o) in selectorTypes ]    
    
from kivy.factory import Factory
for cls in [ ColorSelectorWid, NumSelectorWid, TextSelectorWid , CustomSelectorWidget, CreateSelector, CustomSelectorStarter, FilteredCriteriaCombo, ClearSelectorButton]:
    Factory.register(cls.__name__, cls=cls)

guiCommon.load_kv_file('wineSelectorWidgets.kv')
